package rsa

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
)

/*
   Author: mahaiyuan
   Date: 2021/6/2 10:57 下午
   Description: rsa工具类 主要用于加密、解密、签名、验签
*/

func EncryptBase64(plaintext, publicKey string) (ciphertext string, err error) {
	block, _ := pem.Decode([]byte(publicKey))
	if block == nil {
		err = errors.New("publicKey error")
		return
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return
	}
	pub := pubInterface.(*rsa.PublicKey)
	bytes, err := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte(plaintext))
	if err != nil {
		return
	}
	ciphertext = base64.StdEncoding.EncodeToString(bytes)
	return
}

func DecryptBase64(ciphertext, privateKey string) (plaintext string, err error) {
	bytes, err := base64.StdEncoding.DecodeString(ciphertext)
	if err != nil {
		err = errors.New("invalid ciphertext")
		return
	}

	block, _ := pem.Decode([]byte(privateKey))
	if block == nil {
		err = errors.New("invalid privateKey")
		return
	}
	priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return
	}
	dstBytes, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, bytes)
	if err != nil {
		return
	}
	plaintext = string(dstBytes)
	return
}

func SignSHA256(data, privateKey *string) (sign string, err error) {
	block, _ := pem.Decode([]byte(*privateKey))
	if block == nil {
		err = errors.New("private key invalid")
		return
	}

	priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return
	}

	hash := crypto.SHA256
	instance := hash.New()
	instance.Write([]byte(*data))

	bytes, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, instance.Sum(nil))
	if err != nil {
		return
	}
	sign = base64.StdEncoding.EncodeToString(bytes)
	return
}

func VerifySHA256(sign, orgData, publicKey *string) (rs bool, err error) {

	bytes, err := base64.StdEncoding.DecodeString(*sign)
	if err != nil {
		err = errors.New("invalid sign")
		return
	}

	block, _ := pem.Decode([]byte(*publicKey))
	if block == nil {
		err = errors.New("publicKey error")
		return
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return
	}
	pub := pubInterface.(*rsa.PublicKey)

	hash := crypto.SHA256.New()
	hash.Write([]byte(*orgData))

	err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, hash.Sum(nil), bytes)
	if err != nil {
		rs = false
	} else {
		rs = true
	}
	return
}